#include <iostream>

#include "PatternTable.h"


PatternTable::PatternTable(void) {
}


PatternTable::~PatternTable(void) {
}

// Adds the synonym and its corresponding pattern
// to the table. Empty string arguments are allowed.
// This function is used when the first argument in the pattern-bracket
// is NOT a synonym.
bool PatternTable::addPattern(PatternType patternType, const std::string& synonym, 
	const std::string& arg1, bool perfectMatchNeeded1,
	TreeNode* arg2Expr, bool perfectMatchNeeded2,
	TreeNode* arg3Expr, bool perfectMatchNeeded3) {
		insertNewPatternEntry(patternType, synonym, 
			arg1, NULL, perfectMatchNeeded1, INVALID_ARG,
			"", arg2Expr, perfectMatchNeeded2, INVALID_ARG,
			"", arg3Expr, perfectMatchNeeded3, INVALID_ARG);
		return true;
}

// Overload of the basic addPattern function, this function is used 
// when the first argument in the pattern is actually a synonym.
bool PatternTable::addPattern(PatternType patternType, const std::string& synonym, 
	const std::string& arg1, bool perfectMatchNeeded1, RelationshipArgumentType synType1,
	TreeNode* arg2Expr, bool perfectMatchNeeded2,
	TreeNode* arg3Expr, bool perfectMatchNeeded3) {
		insertNewPatternEntry(patternType, synonym, 
			arg1, NULL, perfectMatchNeeded1, synType1,
			"", arg2Expr, perfectMatchNeeded2, INVALID_ARG,
			"", arg3Expr, perfectMatchNeeded3, INVALID_ARG);
		return true;
}

// Creates a PatternEntry data structure and inserts it into the table.
void PatternTable::insertNewPatternEntry(PatternType patternType, const std::string& synonym, 
	const std::string& arg1, TreeNode* arg1ExprRoot, bool perfectMatchNeeded1, RelationshipArgumentType arg1Type,
	const std::string& arg2, TreeNode* arg2ExprRoot, bool perfectMatchNeeded2, RelationshipArgumentType arg2Type,
	const std::string& arg3, TreeNode* arg3ExprRoot, bool perfectMatchNeeded3, RelationshipArgumentType arg3Type) {
		// Create and initialize pattern entry
		PatternEntry entry;

		entry.patternType = patternType;
		entry.synonym = synonym;
		
		entry.args.push_back(arg1);
		entry.args.push_back(arg2);
		entry.args.push_back(arg3);

		entry.argSynonymTypes.push_back(arg1Type);
		entry.argSynonymTypes.push_back(arg2Type);
		entry.argSynonymTypes.push_back(arg3Type);

		entry.exprArguments.push_back(arg1ExprRoot);
		entry.exprArguments.push_back(arg2ExprRoot);
		entry.exprArguments.push_back(arg3ExprRoot);
		
		entry.perfectMatchRequirementVector.push_back(perfectMatchNeeded1);
		entry.perfectMatchRequirementVector.push_back(perfectMatchNeeded2);
		entry.perfectMatchRequirementVector.push_back(perfectMatchNeeded3);

		// Insert pattern entry to table
		mPatternEntryVector.push_back(entry);
}

int PatternTable::getNumberOfEntries(void) {
	return mPatternEntryVector.size();
}

PatternEntry PatternTable::getPatternEntryAtIndex(int index) {
	// Ensure that 0 <= index < size of pattern entry vector
	if (index < 0 || index >= mPatternEntryVector.size()) {
		cout << "Error in PatternTable::getPatternEntryAtIndex(): index " << index << " requested, but size of pattern entry vector is " << mPatternEntryVector.size() << "!\n";
		return PatternEntry();
	}

	// Here, we are ensured that index exists in the pattern entry vector!
	return mPatternEntryVector.at(index);
}

bool PatternTable::replaceSynonym(const std::string& s1, const std::string& s2) {
	//std::vector<PatternEntry> mPatternEntryVector;

	for (std::vector<PatternEntry>::iterator it = mPatternEntryVector.begin() ; it != mPatternEntryVector.end(); ++it) {
		if (it->synonym.compare(s2) ==0) it->synonym = s1;
		if (it->args[0].compare(s2) ==0) it->args[0] = s1;
		if (it->args[1].compare(s2) ==0) it->args[1] = s1;
		if (it->args[2].compare(s2) ==0) it->args[2] = s1;
	}
	return true;
}
